{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "316b99a1",
   "metadata": {},
   "source": [
    "# 装饰器"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b84b6292",
   "metadata": {},
   "source": [
    "## 基础用法\n",
    "\n",
    "以函数作为参数，并且返回一个新函数的函数是一个装饰器："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "2020b6b2",
   "metadata": {},
   "outputs": [],
   "source": [
    "def dec(f):\n",
    "    print(f'I am decorating function {f.__name__}')\n",
    "    return f"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "3c11fcbf",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "I am decorating function len\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<function len(obj, /)>"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dec(len)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "13ec1b7e",
   "metadata": {},
   "source": [
    "装饰器可以在函数定义时用`@`调用："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "f2c47f04",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "I am decorating function add\n"
     ]
    }
   ],
   "source": [
    "@dec\n",
    "def add(x, y):\n",
    "    return x + y"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9883e4ca",
   "metadata": {},
   "source": [
    "调用`add`相当于调用 `dec(add)`。\n",
    "\n",
    "再如，定义两个装饰器函数，一个将原来的函数值加一，另一个乘二："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "4b0d2fb8",
   "metadata": {},
   "outputs": [],
   "source": [
    "def plus_one(f):\n",
    "    def new_func(x):\n",
    "        return f(x) + 1\n",
    "    return new_func\n",
    "\n",
    "def times_two(f):\n",
    "    def new_func(x):\n",
    "        return f(x) * 2\n",
    "    return new_func"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e5fbe581",
   "metadata": {},
   "source": [
    "定义函数，先乘二再加一："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "b6a0f3f8",
   "metadata": {},
   "outputs": [],
   "source": [
    "@plus_one\n",
    "@times_two\n",
    "def foo(x):\n",
    "    return x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "e316be43",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "27"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "foo(13)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a0c47df2",
   "metadata": {},
   "source": [
    "调用`foo(x)`相当于调用 `plus_one(times_two(foo))(x)`。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f40b91c4",
   "metadata": {},
   "source": [
    "## 装饰器工厂\n",
    "\n",
    "生成装饰器的函数被叫做装饰器工厂。将plus_one一般化为一个名为plus_n的装饰器工厂："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "13d37b27",
   "metadata": {},
   "outputs": [],
   "source": [
    "def plus_n(n):\n",
    "    def plus_dec(f):\n",
    "        def new_func(x):\n",
    "            return f(x) + n\n",
    "        return new_func\n",
    "    return plus_dec"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fbdc86eb",
   "metadata": {},
   "source": [
    "可以将`plus_one`替换为`plus_n(1)`："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "86a01464",
   "metadata": {},
   "outputs": [],
   "source": [
    "@plus_n(1)\n",
    "@times_two\n",
    "def foo(x):\n",
    "    return x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "5b6a2f50",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "27"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "foo(13)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
